#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////

LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecArbre::analyse() {
    arbre = programme();
    cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::programme() {
    // <programme> ::= debut <seqInst> fin <EOF>

    sauterSymCour("debut");
    Noeud* si = seqInst();
    sauterSymCour("fin");
    testerSymCour("<FINDEFICHIER>");
    return si;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::seqInst() {
    // <seqInst> ::= <inst> ; { <inst> ; }

    NoeudSeqInst* si = new NoeudSeqInst();
    do {
        si->ajouteInstruction(inst());
        sauterSymCour(";");
    } while (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour()== "si");
    // tant que le symbole courant est un debut possible d'instruction...
    return si;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::inst() {
    // <inst> ::= <affectation> | <instSi>
    if (ls.getSymCour()=="si")
        return instSi();
    else return affectation();
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::affectation() {
    // <affectation> ::= <variable> = <expression>

    testerSymCour("<VARIABLE>");
    Noeud* var = ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour("=");
    Noeud* exp = expression();
    return new NoeudAffectation(var, exp);
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::expression() {
    // <expression> ::= <terme> { <opAdd> <terme> } 

    Noeud* ter = terme();
    while (ls.getSymCour() == "+" || ls.getSymCour() == "-") {
        Symbole operateur = opAdd(); // on stocke le symbole de l'opérateur
        Noeud* termDroit = terme(); // lecture de l'operande droit
        ter = new NoeudOperateurBinaire(operateur, ter, termDroit); // const. du noeud
    }
    return ter;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::terme() {
    //<terme>::=  <facteur> { <opMult> <facteur> }
    Noeud* fact = facteur();
    while (ls.getSymCour() == "*" || ls.getSymCour() == "/") {
        Symbole operateur = opMult();
        Noeud* factDroit = facteur();
        fact = new NoeudOperateurBinaire(operateur, fact, factDroit);
    }
    return fact;
}

////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opAdd() {
    Symbole operateur;
    if (ls.getSymCour() == "+" || ls.getSymCour() == "-") {
        operateur = ls.getSymCour();
        ls.suivant();
    } else
        erreur("<opAdd>");
    return operateur;
}


////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opMult() {
    Symbole operateur;
    if (ls.getSymCour() == "*" || ls.getSymCour() == "/") {
        operateur = ls.getSymCour();
        ls.suivant();
    } else
        erreur("<opMult>");
    return operateur;
}
////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::facteur() {
    // <facteur> ::= <entier>  |  <variable>  | <opUnaire> <expBool> | ( <expBool> )

    Noeud* fact = NULL;

    if (ls.getSymCour() == "<VARIABLE>" || ls.getSymCour() == "<ENTIER>") {
        fact = ts.chercheAjoute(ls.getSymCour());
        ls.suivant();
    } 
    else if (ls.getSymCour() == "-") {
         //on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
        fact = new NoeudOperateurBinaire(ls.getSymCour(), ts.chercheAjoute(Symbole("0")), facteur()); 
    }
    else if ( ls.getSymCour()=="non") {
        fact = new NoeudOperateurBinaire (ls.getSymCour(), ts.chercheAjoute(Symbole("non")), facteur());
    }
    else if (ls.getSymCour() == "(") {
        ls.suivant();
        fact = expBoolOu();
        sauterSymCour(")");
    }
    else
        erreur("<facteur>");
    return fact;
}


////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::expBoolOu() {
  //<exBoolOu>::= <expBoolEt> { <opOu> <expBoolEt> }
    Noeud* expBE = expBoolEt();
    while (ls.getSymCour() == "ou") {
        Symbole opB = opBoolOu();
        Noeud * relDroite = relation();
        expBE = new NoeudOperateurBinaire(opB, expBE, relDroite);
    }
    return expBE;
}


////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::expBoolEt() {
  //<exBoolEt>::= <relation> { <opEt> <relation> }
    Noeud* rel = relation();
    while (ls.getSymCour() == "et") {
        Symbole opB = opBoolEt();
        Noeud * relDroite = relation();
        rel = new NoeudOperateurBinaire(opB, rel, relDroite);
    }
    return rel;
}


////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opBoolOu() {
    //<opBoolOu>::= ou
    Symbole operateur;
    if (ls.getSymCour() == "ou") {
        operateur = ls.getSymCour();
        ls.suivant();
    } else
        erreur("<opBoolOu>");
    return operateur;
}



////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opBoolEt() {
    //<opBoolEt>::= et
    Symbole operateur;
    if (ls.getSymCour() == "et") {
        operateur = ls.getSymCour();
        ls.suivant();
    } else
        erreur("<opBoolEt>");
    return operateur;
}


////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opBoolEt() {
    //<opBoolEt>::= et
    Symbole operateur;
    if (ls.getSymCour() == "et") {
        operateur = ls.getSymCour();
        ls.suivant();
    } else
        erreur("<opBoolEt>");
    return operateur;
}
////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::relation() {
    //<relation>::= <expression> { <opRel> <expression> }
    Noeud * exp = expression();
    while (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<" ||
            ls.getSymCour() == "<=" || ls.getSymCour() == ">" || ls.getSymCour() == ">=") {
        Symbole opR = opRel();
        Noeud * expDroite = expression();
        exp = new NoeudOperateurBinaire(opR, exp, expDroite);
    }
    return exp;
}

////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opRel() {
    //<opRel>::= == | != | < | <= | > | >=
    Symbole operateur;
    if (ls.getSymCour() == "==" || ls.getSymCour() == "!=" || ls.getSymCour() == "<" ||
            ls.getSymCour() == "<=" || ls.getSymCour() == ">" || ls.getSymCour() == ">=") {
        operateur = ls.getSymCour();
        ls.suivant();
    } else
        erreur("<opBool>");
    return operateur;
}



///////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instSi() {
  //<instSi>::= si ( <expBoolEt> ) <seqInst> { sinonsi ( <expBoolEt> ) <seqInst> } [ sinon <seqInst> ] finsi
    sauterSymCour("si");
    sauterSymCour("(");
    Noeud* expBS = expBoolEt();
    sauterSymCour(")");
    Noeud* seqIS = seqInst();
    
    while (ls.getSymCour()=="sinonsi") {
        sauterSymCour("sinonsi");
        sauterSymCour("(");
        Noeud * expBSS = expBoolEt();
        sauterSymCour(")");
        Noeud * seqISS = seqInst();
    }
    
    if (ls.getSymCour()=="sinon") {
        sauterSymCour("sinon");
        Noeud* seqISin= seqInst();
    }
    
    sauterSymCour ("finsi");
    return intS = new NoeudSi(expBS, seqIS, );
    
    ///////////////FINIR IIIICCCCIIII !!!!!!!!!
}


////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecArbre::testerSymCour(string ch) {
    if (ls.getSymCour() != ch) {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
                << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
                << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
                << endl;
        exit(0); // plus tard, on levera une exception
    }
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
    testerSymCour(ch);
    ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////

void LecteurPhraseAvecArbre::erreur(string mess) {
    cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
            << ls.getColonne() << endl << "   Attendu : " << mess << endl
            << "   Trouve  : " << ls.getSymCour() << endl << endl;
    exit(0); // plus tard, on levera une exception
}
